/*
 * Created on 07-may-2005
 *
 * To change the template for this generated file go to
 * Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
 */
package org.jma.lib.utils.multithreading;

import java.util.*;



/**
 * @author Jes�s
 *
 * To change the template for this generated type comment go to
 * Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
 */
public class Mutex {
	static final int MAX_TIME_WAITING=15000;
	static Vector MutexPerApplication=new Vector();
	Thread owner=null;
	int numberOfLocksPerThread=0;
	int timeWaiting=5000;
	
	public Mutex() {
		super();
		owner=null;
		numberOfLocksPerThread=0;
		MutexPerApplication.add(this);
	}
	
	public String toString(){
		String name;

		if (owner==null) name="null";
		else {
			name=owner.getName();
		}
		return ("<"+super.toString()+" owner:"+name+">");
	}
	
	public synchronized void lock(){
		boolean interrumped=false;
		int tempo=0;
		Random rn =new Random(System.currentTimeMillis());
		timeWaiting= rn.nextInt() % 5000;
		if (timeWaiting<0) timeWaiting*= -1;
		while(owner!=null && !Thread.currentThread().equals(owner)){
			try{	
				wait(timeWaiting);
				timeWaiting= rn.nextInt() % 5000;
				if (timeWaiting<0) timeWaiting*= -1;
				tempo+=timeWaiting;
				System.out.println(Thread.currentThread().getName()+" Says: I've been "+tempo+"ms waiting for thread "+this.toString());
				if (tempo>MAX_TIME_WAITING) {
					System.out.println(Thread.currentThread().getName()+" Says: sorry, I  steal the lock to "+this.toString());
					stealLock(Thread.currentThread());
				}
			}catch (InterruptedException ie){
				interrumped=true;
			}
		}
	
		owner=Thread.currentThread();
		numberOfLocksPerThread++;
	
		if (interrumped) Thread.currentThread().interrupt();
	}

	private void stealLock(Thread thread) {
		try{
		int it=0;
		int numLocks=MutexPerApplication.size();
		Thread oldOwner=owner;
		
		while (it<numLocks){
			Mutex mu = (Mutex) MutexPerApplication.get(it);
			if (mu.owner==oldOwner){ 
				mu.owner=null;
				mu.numberOfLocksPerThread=0;
				mu.timeWaiting=0;
			}
			it++;
		}
		}catch(Exception e){
			
		}
	}

	public synchronized void unlock(){
			
			if (owner==null) return;
			if (!owner.equals(Thread.currentThread())){
				System.out.println(Thread.currentThread()+" Not owner, it is "+toString());
				return;
			}
			
			numberOfLocksPerThread--;
			if (numberOfLocksPerThread<0) {
				throw new IllegalMonitorStateException(toString()+" to many unlock, repair the code?¿?¿?***************************");
			}
			if (numberOfLocksPerThread==0) {
				owner=null;
				notify();
			}
			
	}
	
	
	public synchronized boolean isMine(){
		return (owner.equals(Thread.currentThread()));
	}
	
	protected void finalize() {
		MutexPerApplication.remove(this);
	}

}


